package directory_sync;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import org.apache.log4j.Logger;

public class SyncRunner
{
	private int progress;
	//logging
	private Logger logger;
	//progress bar
	private DisplayProgress progressBar;
	//all files and directories with its absolute path
	private List<File> sourceDirList;
	private List<File> targetDirList;
	//source and target directories
	private String source;
	private String target;

	public SyncRunner(String aSourceDir, String aTargetDir, Logger aLogger)
	{
		source = aSourceDir;
		target = aTargetDir;
		logger = aLogger;
		progressBar = new DisplayProgress(logger);
		
		SyncReader readSourceDir = new SyncReader(source);
		sourceDirList = readSourceDir.getFileList();
		SyncReader readTargetDir = new SyncReader(target);
		targetDirList = readTargetDir.getFileList();
		syncDirectories();
		logger.info("Source and target are now synchronized");
		runCleanup();
	}
	
	public void syncDirectories()
	{
		int sourceDirLength = source.length();
		
		logger.info("RUN SYNC------------------------------");
		logger.info("From: " + source);
		logger.info("To: " + target);
		logger.info("Number of objects to sync: " + sourceDirList.size());
		
		for (int i = 0; i < sourceDirList.size(); i++)
		{
			if(i != 0)
			{
				float part = (sourceDirList.size()-i);
				float total = sourceDirList.size();
				progress = (int)(101-((part/total)*100));
				System.out.println("Object " + i + " - " + progress + " %");
				logger.debug("Current progress count: " + progress);
				progressBar.setProgress(progress, sourceDirList.get(i).toString());
			}
			if (sourceDirList.get(i).isFile())
			{
				//set source and target file
				File sourcefile = new File(sourceDirList.get(i).getAbsolutePath());
				File targetfile = new File(target + sourceDirList.get(i).getAbsolutePath().substring(sourceDirLength));

				logger.debug("Processing object: " + sourcefile.getPath());
				logger.debug("From: " + sourcefile.getPath());
				logger.debug("To: " + targetfile.getPath());
				
				//if target file already exists
				if(targetfile.exists())
				{
					boolean replace;
					replace = fileCompare(sourcefile, targetfile);
					
					if(replace)
					{
						logger.debug("Replace file: " + targetfile);
						try
						{
							copyFile(sourcefile, targetfile);
						}
						catch(IOException ex)
						{
							logger.error("Not able to copy file: " + sourcefile);
							logger.error(ex);
							ex.printStackTrace();
						}
						syncDate(sourcefile, targetfile);
					}
				}
				else
				{
					logger.debug("Create file: " + targetfile);
					try
					{
						copyFile(sourcefile, targetfile);
					}
					catch(IOException ex)
					{
						logger.error("Not able to copy file: " + sourcefile);
						logger.error(ex);
						ex.printStackTrace();
					}
					syncDate(sourcefile, targetfile);
				}
			}
			else
			{
				//set source and target directory
				File sourceDirectory = new File(sourceDirList.get(i).getAbsolutePath());
				File targetDirectory = new File(target + sourceDirList.get(i).getAbsolutePath().substring(sourceDirLength));

				//if target directory already exists
				if(targetDirectory.exists())
				{
					boolean replace;
					replace = fileCompare(sourceDirectory, sourceDirectory);
					
					if(replace)
					{
						logger.debug("Create directory: " + targetDirectory);
						createDirectory(targetDirectory);
					}
				}
				else
				{
					logger.debug("Create directory: " + targetDirectory);
					createDirectory(targetDirectory);
				}
			}
		}
	}
	
	public boolean fileCompare(File sourceFile, File targetFile)
	{
		boolean replace;
		
		long sourceFileDate = sourceFile.lastModified();
		long targetFileDate = targetFile.lastModified();
		
		if(sourceFileDate == targetFileDate)
		{
			replace = false;
		}
		else if(sourceFileDate < targetFileDate) 
		{
			replace = false;
		}
		else
		{
			replace = true;
		}
		
		return replace;
	}
	
	public void syncDate(File sourceFile, File targetFile)
	{
		targetFile.setLastModified(sourceFile.lastModified());
	}

	public void copyFile(File inputFile, File outputFile) throws IOException
	{
		inputFile = new File(inputFile.getAbsolutePath());
		outputFile = new File(outputFile.getAbsolutePath());
	    InputStream inputStream = new FileInputStream(inputFile);
	    OutputStream outputStream = new FileOutputStream(outputFile);

	    byte[] buffer = new byte[1024];
	    int length;
	    while ((length = inputStream.read(buffer)) > 0)
	    {
	    	outputStream.write(buffer, 0, length);
	    }
	    inputStream.close();
	    outputStream.close();
	}
	
	public void createDirectory(File directory)
	{
		File createDirectory = new File(directory.getAbsolutePath());
		createDirectory.mkdir();
	}
	
	public void runCleanup()
	{
		int targetDirLenth = target.length();
		
		logger.info("RUN CLEANUP---------------------------");
		logger.info("From: " + source);
		logger.info("To: " + target);
		
		for(int i=targetDirList.size()-1; i>-1; i--)
		{
			File targetDirFile = new File(targetDirList.get(i).getAbsolutePath());
			File sourceDirFile = new File(source + targetDirList.get(i).getAbsolutePath().substring(targetDirLenth));
			
			if(targetDirList.get(i).isFile())
			{
				if(sourceDirFile.exists())
				{
					logger.debug("Source file exists: " + sourceDirFile);
				}
				else
				{
					logger.debug("Delete file: " + targetDirFile);
					targetDirFile.delete();
				}
			}
			else
			{
				if(sourceDirFile.exists())
				{
					logger.debug("Source folder exists: " + sourceDirFile);
				}
				else
				{
					logger.debug("Delete file: " + targetDirFile);
					targetDirFile.delete();
				}
			}
		}
	}
	
	protected int getProgress()
	{
		return progress;
	}
}